# -*- coding: cp1252 -*-
import sys
import xmpp
import threading
import thread
import Queue
import time
import MessageReceiver
import AID
import XMLCodec
import ACLParser
import Envelope
import ACLMessage
import BasicFipaDateTime
import Behaviour
import SL0Parser
import colors
import mutex
#from AMS import AmsAgentDescription

# Taken from xmpp debug
color_none         = chr(27) + "[0m"
color_black        = chr(27) + "[30m"
color_red          = chr(27) + "[31m"
color_green        = chr(27) + "[32m"
color_brown        = chr(27) + "[33m"
color_blue         = chr(27) + "[34m"
color_magenta      = chr(27) + "[35m"
color_cyan         = chr(27) + "[36m"
color_light_gray   = chr(27) + "[37m"
color_dark_gray    = chr(27) + "[30;1m"
color_bright_red   = chr(27) + "[31;1m"
color_bright_green = chr(27) + "[32;1m"
color_yellow       = chr(27) + "[33;1m"
color_bright_blue  = chr(27) + "[34;1m"
color_purple       = chr(27) + "[35;1m"
color_bright_cyan  = chr(27) + "[36;1m"
color_white        = chr(27) + "[37;1m"



class AbstractAgent(MessageReceiver.MessageReceiver):
    """
    Abstract Agent
    only for heritance
    Child classes: PlatformAgent, Agent
    """
    
    def __init__(self, agentjid, serverplatform):
	"""
	inits an agent with a JID (user@server) and a platform JID (acc.platformserver)
	"""
        MessageReceiver.MessageReceiver.__init__(self)
        self._aid = AID.aid(name=agentjid, addresses=[ "xmpp://"+agentjid ])
        self._jabber = None
        self._serverplatform = serverplatform
        self._defaultbehaviour = None
        self._behaviourList = dict()
        self._alive = True
	self._alivemutex = mutex.mutex()
	self._forceKill = threading.Event()
	self._forceKill.clear()

	self.setName(str(agentjid))

	self._friend_list = []  # Legacy
	self._muc_list= {}
	self._roster = None
	self._subscribeHandler   = lambda frm,typ,stat,show: False
	self._unsubscribeHandler = lambda frm,typ,stat,show: False


    def _jabber_presenceCB(self, conn, mess):
	"""
	presence callback
	manages jabber stanzas of the 'presence' protocol
	"""

	frm=None
	
	ifrm = mess.getFrom()
	if ifrm:
		frm = AID.aid(str(mess.getFrom()), ['xmpp://'+str(mess.getFrom())])
		#check for MUC presence
		if ifrm.getDomain() == self.getMUC():
			if self._muc_list.has_key(str(ifrm.getNode())):
				self._muc_list[ifrm.getNode()].presenceCB(mess)

		else:
			typ = str(mess.getType())
			status = str(mess.getStatus())
			show = str(mess.getShow())

			if typ in ['subscribe']: #, 'subscribed']:
				# Call the subscribe handler
				if self._subscribeHandler(frm, typ, status, show):
					reply = xmpp.Presence(mess.getFrom(), 'subscribed')
					conn.send(reply)
					return
			elif typ in ['unsubscribe']: #, 'unsubscribed']:
				# Call the unsubscribe handler
				if self._unsubscribeHandler(frm, typ, status, show):
					reply = xmpp.Presence(mess.getFrom(), 'unsubscribed')
					conn.send(reply)
				return
			else:
				# Unsupported presence message
				pass

			# Pass the FIPA-message to the behaviours
			for b in self._behaviourList:
				b.managePresence(frm, typ, status, show)

			self._defaultbehaviour.managePresence(frm, typ, status, show)

			#self._roster = conn.getRoster()

    def _jabber_messageCB(self, conn, mess):
	"""
	message callback
	read the message envelope and post the message to the agent
	"""
        if (mess.getError() == None):
            envxml=None
            payload=mess.getBody()
            children = mess.getChildren()
            for child in children:
                if (child.getNamespace() == "jabber:x:fipa") or (child.getNamespace() == u"jabber:x:fipa"):
                    envxml = child.getData()
            if (envxml != None):
                xc = XMLCodec.XMLCodec()
                envelope = xc.parse(str(envxml))

		
		if   str(envelope.getAclRepresentation()).lower() == "fipa.acl.rep.string.std":
			ac = ACLParser.ACLParser()
		elif str(envelope.getAclRepresentation()).lower() == "fipa.acl.rep.xml.std":
			ac = ACLParser.ACLxmlParser()
		else:
			print "NO TENGO PARSER!"

                ACLmsg = ac.parse(str(payload))
	        content = ACLmsg.getContent()
        	comillas_esc = '"'
	        barrainv_esc = '\\'
	        mtmp1 = comillas_esc.join(content.split('\\"'))
        	mtmp2 = barrainv_esc.join(mtmp1.split('\\\\'))
	        payload_esc = mtmp2
		ACLmsg.setContent(payload_esc)

		### If the message is directed to a MUC room it is posted directly
		frm = mess.getFrom()
		if frm.getDomain() == self.getMUC():
			if self._muc_list.has_key(str(frm.getNode())):
				self._muc_list[frm.getNode()].postMessage(ACLmsg)
		else:
			self.postMessage(ACLmsg)
            else:
                self._other_messageCB(conn,mess)

	return True


    def _other_messageCB(self, conn, mess):
	"""
	non jabber:x:fipa chat messages callback
	"""
	#print "NON-FIPA MESSAGE RECEIVED: " + str(mess)
        pass

    
    def getAID(self):
	"""
	returns AID
	"""
        return self._aid

    def getAMS(self):
	"""
	returns the AMS aid
	"""
        return AID.aid(name="ams." + self._serverplatform, addresses=[ "xmpp://acc."+self._serverplatform ])

    def getDF(self):
	"""
	returns the DF aid
	"""
        return AID.aid(name="df." + self._serverplatform, addresses=[ "xmpp://acc."+self._serverplatform ])

    def getMUC(self):
	"""
	returs the MUC JID
	"""
	return "muc."+self._serverplatform

    def getSpadePlatformJID(self):
	"""
	returns the SPADE JID (string)
	"""
        return "acc." + self._serverplatform
    
    def send(self, ACLmsg):
	"""
	sends an ACLMessage
	"""
        #self._sendTo(ACLmsg, self.getSpadePlatformJID())
        self._sendTo(ACLmsg, ACLmsg.getReceivers())

    def _sendTo(self, ACLmsg, tojid):
	"""
	sends an ACLMessage to a specific JabberID
	"""
        if (ACLmsg.getSender() == None):
            ACLmsg.setSender(self.getAID())

        content = ACLmsg.getContent()
        comillas_esc = '\\"'
        barrainv_esc = '\\\\'
        mtmp1 = barrainv_esc.join(content.split('\\'))
        mtmp2 = comillas_esc.join(mtmp1.split('"'))
        payload_esc = mtmp2
        ACLmsg.setContent(payload_esc)
        
	ap = ACLParser.ACLxmlParser();
        payload = ap.encodeXML(ACLmsg)
        
        envelope = Envelope.Envelope()
        envelope.setFrom(ACLmsg.getSender())
        for i in ACLmsg.getReceivers():
            envelope.addTo(i)
        envelope.setAclRepresentation("fipa.acl.rep.xml.std")
        envelope.setPayloadLength(len(payload))
        envelope.setPayloadEncoding("US-ASCII")
        envelope.setDate(BasicFipaDateTime.BasicFipaDateTime())

        
        xc = XMLCodec.XMLCodec()
        envxml = xc.encodeXML(envelope)

        xenv = xmpp.protocol.Node('jabber:x:fipa x')
        xenv['content-type']='fipa.mts.env.rep.xml.std'
        xenv.addData(envxml)
        
	to = tojid[0]
	jabber_msg = xmpp.protocol.Message(to.getName(),payload, xmlns="")
        jabber_msg.addChild(node=xenv)
        jabber_msg["from"]=self.getAID().getName()
        self.jabber.send(jabber_msg)
    
    def _kill(self):
	"""
	kills the agent
	"""
        #self._alive = False
	self._forceKill.set()

    def isRunning(self):
	"""
	returns wether an agent is running or not
	"""
	return self._alive

    def stop(self, timeout=0):
	"""
	Stops the agent execution and blocks until the agent dies
	"""
	self._kill()
	if timeout > 0:
		to = time.now() + timeout
		while self._alive and time.now() < to:
			time.sleep(0.1)
	# No timeout (true blocking)
	else:
		while self._alive:
			time.sleep(0.1)
	return True
  
    def forceKill(self):
            return self._forceKill.isSet()
        
    def _setup(self):
	"""
	setup agent method. configures the agent
	must be overridden
        """
        pass

    def takeDown(self):
	"""
	stops the agent
	must be overridden
        """
        pass


    def run(self):
	"""
	periodic agent execution
	"""
        #Init The agent
        self._setup()
        #Start the Behaviours
        if (self._defaultbehaviour != None):
            self._defaultbehaviour.start()
        #Main Loop
        while not self.forceKill():
        	try:
               		#Check for queued messages
	                proc = False
        	        msg = self._receive(block=True, timeout=0.01)
	                if msg != None:
        	            for b in self._behaviourList:
                	        t = self._behaviourList[b]
                        	if (t != None):
	                            if (t.match(msg) == True):
        	                        b.postMessage(msg)
                	                #if (b.done() == True):
                        	        #    self.removeBehaviour(b)
	                                proc = True
        	                        break #should break?
                	    if (proc == False):
                        	if (self._defaultbehaviour != None):
	                       		self._defaultbehaviour.postMessage(msg)
	        except:
	            self._kill()

	self._shutdown()
            
    def setDefaultBehaviour(self, behaviour):
	"""
	sets a Behavior as Default
	"""
        self._defaultbehaviour = behaviour
        behaviour.setAgent(self)

    def getDefaultBehaviour(self):
	"""
	returns the default behavior
	"""
        return self._defaultbehaviour

    def addBehaviour(self, behaviour, template=None):
	"""
	adds a new behavior to the agent
	"""
        self._behaviourList[behaviour] = template
        behaviour.setAgent(self)
        behaviour.start()

    def removeBehaviour(self, behaviour):
	"""
	removes a behavior from the agent
	"""
        behaviour.kill()
        try:
            self._behaviourList.pop(behaviour)
        except KeyError:
	    #print "removeBehaviour: KeyError"
            pass

    def subscribeToFriend(self, aid):
	"""
	presence subscription to another agent
	"""
	pass

    def unsubscribeToFriend(self, aid):
	"""
	presence unsubscription to another agent
	"""
	pass

    def getRoster(self):
	"""
	get roster of friends
	"""
	return self._roster

    def registerSubscribeHandler(self, handler):
	"""
	register the handler that will manage incoming presence subscriptions (agent level)
	"""
	self._subscribeHandler = handler

    def registerUnsubscribeHandler(self, handler):
	"""
	register the handler that will manage incoming presence unsubscriptions (agent level)
	"""
	self._unsubscribeHandler = handler

    class SearchAgentBehaviour(Behaviour.OneShotBehaviour):
        def __init__(self, msg, AAD, debug = False):
            Behaviour.OneShotBehaviour.__init__(self)
            self.AAD = AAD
            self.debug = debug
            self.result = None
            self.finished = False
            self._msg = msg

        def _process(self):
            p = SL0Parser.SL0Parser()
            self._msg.addReceiver( self.myAgent.getAMS() )
            self._msg.setPerformative('request')
            self._msg.setLanguage('fipa-sl0')
            self._msg.setProtocol('fipa-request')
            self._msg.setOntology('FIPA-Agent-Management')
            
            content = "((action "
            content += str(self.myAgent.getAID())
            content += "(search "+ str(self.AAD) +")"
            content +=" ))"
            
            self._msg.setContent(content)
            self.myAgent.send(self._msg)
            msg = self._receive(True,10)
            if msg == None or str(msg.getPerformative()) != 'agree':
                print "There was an error searching the Agent. (not agree)"
                if self.debug:
                    print str(msg)
                self.finished = True
                return None
            msg = self._receive(True,20)
            if msg == None or msg.getPerformative() != 'inform':
                print "There was an error searching the Agent. (not inform)"
                if self.debug:
                    print str(msg)
                self.finished = True
                return None
            else:
                content = p.parse(msg.getContent())
                if self.debug:
                    print str(msg)
                self.result = [] #content.result.set
		for i in content.result.set:
			#self.result.append(AmsAgentDescription(i)) #TODO: no puedo importar AMS :(
			#print str(i[1])
			self.result.append(i[1])
            self.finished = True

    def searchAgent(self, AAD, debug=False):
	"""
	searches an agent in the AMS
	the search template is an AmsAgentDescription class
	"""
        msg = ACLMessage.ACLMessage()
        template = Behaviour.ACLTemplate()
        template.setConversationId(msg.getConversationId())
        t = Behaviour.MessageTemplate(template)
        b = AbstractAgent.SearchAgentBehaviour(msg, AAD, debug)
        
        self.addBehaviour(b,t)
        b.join()
        return b.result
        
    
    class ModifyAgentBehaviour(Behaviour.OneShotBehaviour):
        def __init__(self, AAD, debug = False):
            Behaviour.OneShotBehaviour.__init__(self)
            self.AAD = AAD
            self.debug = debug
            self.result = None
            self.finished = False
            self._msg = ACLMessage()

        def _process(self):
            p = SL0Parser.SL0Parser()
            self._msg.addReceiver( self.myAgent.getAMS() )
            self._msg.setPerformative('request')
            self._msg.setLanguage('fipa-sl0')
            self._msg.setProtocol('fipa-request')
            self._msg.setOntology('FIPA-Agent-Management')
            
            content = "((action "
            content += str(self.myAgent.getAID())
            content += "(modify "+ str(self.AAD) + ")"
            content +=" ))"

            self._msg.setContent(content)
            	
            self.myAgent.send(self._msg)

            msg = self._receive(True,20)
            if msg == None or msg.getPerformative() != 'agree':
                print "There was an error modifying the Agent. (not agree)"
                if self.debug:
                    print str(msg)
                self.result = False
                return -1
            msg = self._receive(True,20)
            if msg == None or msg.getPerformative() != 'inform':
                print "There was an error modifying the Agent. (not inform)"
                if self.debug:
                    print str(msg)
                self.result = False
                return -1
            self.result = True
            return 1

    def modifyAgent(self, AAD, debug=False):
	"""
	modifies the AmsAgentDescription of an agent in the AMS
	"""
        template = Behaviour.ACLTemplate()
        template.setConversationId(msg.getConversationId())
        t = Behaviour.MessageTemplate(template)
        b = AbstractAgent.ModifyAgentBehaviour(msg, AAD, debug)
        
        self.addBehaviour(b,t)
        b.join()
        return b.result


    class getPlatformInfoBehaviour(Behaviour.OneShotBehaviour):
        def __init__(self, msg, debug = False):
            Behaviour.OneShotBehaviour.__init__(self)
            self._msg = msg
            self.debug = debug
            self.result = None
            self.finished = False

	def _process(self):
		msg = self._msg
		msg.addReceiver( self.myAgent.getAMS() )
		msg.setPerformative('request')
		msg.setLanguage('fipa-sl0')
		msg.setProtocol('fipa-request')
		msg.setOntology('FIPA-Agent-Management')
				
		content = "((action "
		content += str(self.myAgent.getAID())
		content += "(get-description platform)"
		content +=" ))"

		msg.setContent(content)
		
		self.myAgent.send(msg)

		msg = self._receive(True,20)
		if msg == None or msg.getPerformative() != 'agree':
			print "There was an error modifying the Agent. (not agree)"
			if self.debug:
				print str(msg)
			return -1
		msg = self._receive(True,20)
		if msg == None or msg.getPerformative() != 'inform':
			print "There was an error modifying the Agent. (not inform)"
			if self.debug:
				print str(msg)
			return -1

		self.result = msg.getContent()

    def getPlatformInfo(self, debug=False):
	"""
	returns the Plarform Info
	"""
	msg = ACLMessage.ACLMessage()
        template = Behaviour.ACLTemplate()
        template.setConversationId(msg.getConversationId())
        t = Behaviour.MessageTemplate(template)
        b = AbstractAgent.getPlatformInfoBehaviour(msg, debug)
        
        self.addBehaviour(b,t)
        b.join()
        return b.result
	

	##################################
    
    class registerServiceBehaviour(Behaviour.OneShotBehaviour):	    
    	def __init__(self, msg, DAD, debug = False):
            Behaviour.OneShotBehaviour.__init__(self)
            self._msg = msg
	    self.DAD = DAD
            self.debug = debug
            self.result = None
            self.finished = False

	def _process(self):
		self._msg.addReceiver( self.myAgent.getDF() )
		self._msg.setPerformative('request')
		self._msg.setLanguage('fipa-sl0')
		self._msg.setProtocol('fipa-request')
		self._msg.setOntology('FIPA-Agent-Management')
				
		content = "((action "
		content += str(self.myAgent.getAID())
		content += "(register " + str(self.DAD) + ")"
		content +=" ))"

		self._msg.setContent(content)
		
		self.myAgent.send(self._msg)

		msg = self._receive(True,20)
		if msg == None or msg.getPerformative() != 'agree':
			print "There was an error registering the Service. (not agree)"
			if self.debug:
				print str(msg)
			self.result = False
			return
		msg = self._receive(True,20)
		if msg == None or msg.getPerformative() != 'inform':
			print "There was an error registering the Service. (not inform)"
			if self.debug:
				print str(msg)
			self.result = False
			return
	
		if self.debug:
			print str(msg)
		self.result = True

    def registerService(self, DAD, debug=False):
	"""
	registers a service in the DF
	the service template is a DfAgentDescriptor
	"""
	msg = ACLMessage.ACLMessage()
        template = Behaviour.ACLTemplate()
        template.setConversationId(msg.getConversationId())
        t = Behaviour.MessageTemplate(template)
        b = AbstractAgent.registerServiceBehaviour(msg=msg, DAD=DAD, debug=debug)
        
        self.addBehaviour(b,t)
        b.join()
        return b.result 
  
    class deregisterServiceBehaviour(Behaviour.OneShotBehaviour):
	def __init__(self, msg, DAD, debug=False):
            Behaviour.OneShotBehaviour.__init__(self)
            self._msg = msg
	    self.DAD = DAD
            self.debug = debug
            self.result = None
            self.finished = False

	def _process(self):
		self._msg.addReceiver( self.myAgent.getDF() )
		self._msg.setPerformative('request')
		self._msg.setLanguage('fipa-sl0')
		self._msg.setProtocol('fipa-request')
		self._msg.setOntology('FIPA-Agent-Management')
				
		content = "((action "
		content += str(self.myAgent.getAID())
		content += "(deregister " + str(self.DAD) + ")"
		content +=" ))"

		self._msg.setContent(content)
		
		self.myAgent.send(self._msg)

		msg = self._receive(True,20)
		if msg == None or msg.getPerformative() != 'agree':
			print "There was an error deregistering the Service. (not agree)"
			if self.debug:
				print str(msg)
			self.result = False
			return
		msg = self._receive(True,20)
		if msg == None or msg.getPerformative() != 'inform':
			print "There was an error deregistering the Service. (not inform)"
			if self.debug:
				print str(msg)
			self.result = False
			return
	
		if self.debug:
			print str(msg)
		self.result = True
		return

    def deregisterService(self, DAD, debug=False):
	"""
	deregisters a service in the DF
	the service template is a DfAgentDescriptor
	"""
	msg = ACLMessage.ACLMessage()
        template = Behaviour.ACLTemplate()
        template.setConversationId(msg.getConversationId())
        t = Behaviour.MessageTemplate(template)
        b = AbstractAgent.deregisterServiceBehaviour(msg, DAD, debug)
        
        self.addBehaviour(b,t)
        b.join()
        return b.result 
  
    class searchServiceBehaviour(Behaviour.OneShotBehaviour):

	def __init__(self, msg, DAD, debug=False):
            Behaviour.OneShotBehaviour.__init__(self)
            self._msg = msg
	    self.DAD = DAD
            self.debug = debug
            self.result = None
            self.finished = False


	def _process(self):	

		self._msg.addReceiver( self.myAgent.getDF() )
		self._msg.setPerformative('request')
		self._msg.setLanguage('fipa-sl0')
		self._msg.setProtocol('fipa-request')
		self._msg.setOntology('FIPA-Agent-Management')
				
		content = "((action "
		content += str(self.myAgent.getAID())
		content += "(search "+ str(self.DAD) +")"
		content +=" ))"
	
		self._msg.setContent(content)

		self.myAgent.send(self._msg)
	
		msg = self._receive(True,20)
		if msg == None or msg.getPerformative() != 'agree':
			print "There was an error searching the Agent. (not agree)"
			if self.debug:
				print str(msg)
			return
		msg = self._receive(True,20)
		if msg == None or msg.getPerformative() != 'inform':
			print "There was an error searching the Agent. (not inform)"
			if self.debug:
				print str(msg)
			return
	
		else:
			try:
				p = SL0Parser.SL0Parser()
				content = p.parse(msg.getContent())
				if self.debug:
					print str(msg)
				self.result = content.result.set#[0]#.asList()

			except:
				return
    def searchService(self, DAD, debug=False):
	"""
	search a service in the DF
	the service template is a DfAgentDescriptor
	"""
	msg = ACLMessage.ACLMessage()
        template = Behaviour.ACLTemplate()
        template.setConversationId(msg.getConversationId())
        t = Behaviour.MessageTemplate(template)
        b = AbstractAgent.searchServiceBehaviour(msg, DAD, debug)
        
        self.addBehaviour(b,t)
        b.join()
        return b.result 
  

    class modifyServiceBehaviour(Behaviour.OneShotBehaviour):
	def __init__(self, msg, DAD, debug=False):
            Behaviour.OneShotBehaviour.__init__(self)
            self._msg = msg
	    self.DAD = DAD
            self.debug = debug
            self.result = None

	def _process(self):

		#p = SL0Parser.SL0Parser()
	
		self._msg = ACLMessage.ACLMessage()
		self._msg.addReceiver( self.myAgent.getDF() )
		self._msg.setPerformative('request')
		self._msg.setLanguage('fipa-sl0')
		self._msg.setProtocol('fipa-request')
		self._msg.setOntology('FIPA-Agent-Management')
				
		content = "((action "
		content += str(self.myAgent.getAID())
		content += "(modify "+ str(self.DAD) + ")"
		content +=" ))"

		self._msg.setContent(content)
		
		self.myAgent.send(self._msg)

		msg = self._receive(True,20)
		if msg == None or msg.getPerformative() != 'agree':
			print "There was an error modifying the Service. (not agree)"
			if self.debug:
				print str(msg)
			self.result=False
			return
		msg = self._receive(True,20)
		if msg == None or msg.getPerformative() != 'inform':
			print "There was an error modifying the Service. (not inform)"
			if self.debug:
				print str(msg)
			self.result = False
			return

		self.result = True
		return
    def modifyService(self, DAD, debug=False):
	"""
	modifies a service in the DF
	the service template is a DfAgentDescriptor
	"""
	msg = ACLMessage.ACLMessage()
        template = Behaviour.ACLTemplate()
        template.setConversationId(msg.getConversationId())
        t = Behaviour.MessageTemplate(template)
        b = AbstractAgent.modifyServiceBehaviour(msg, DAD, debug)
        
        self.addBehaviour(b,t)
        b.join()
        return b.result 


	##################################

# Changed to be a 'daemonic' python Thread
class jabberProcess(threading.Thread):

	def __init__(self, socket, owner):
		self.jabber = socket
		#self._alive = True
		self._forceKill = threading.Event()
		self._forceKill.clear()
		threading.Thread.__init__(self)
		self.setDaemon(False)
		self._owner = owner
		
	def _kill(self):
		try:
			self._forceKill.set()
		except:
			#Agent is already dead
			pass

	def forceKill(self):
		return self._forceKill.isSet()

	def run(self):
		"""
		periodic jabber update
		"""
		while not self.forceKill():
		    try:
		            err = self.jabber.Process(0.4)
			    #print "Process returns " + str(err) + " " + str(type(err))
		    except:
			    print color_red + "Jabber connection failed: " + color_yellow + str(self._owner.getAID().getName()) + color_red + " (dying)" + color_none
			    self._kill()
		    	    self._owner.stop()
		    if err == None or err == 0:  # None or zero the integer, socket closed
			    print color_red + "Agent disconnected: " + color_yellow + str(self._owner.getAID().getName()) + color_red + " (dying)" + color_none
			    self._kill()
		    	    self._owner.stop()

		

class PlatformAgent(AbstractAgent):
    """
    A PlatformAgent is a SPADE component.
    Examples: AMS, DF, ACC, ...
    """
    def __init__(self, node, password, server="localhost", port=5347, debug = []):
        AbstractAgent.__init__(self, node, server)
	self.debug = debug
        self.jabber = xmpp.Component(server, port, self.debug)
        self._register(password)

    def _register(self, password, autoregister=True):
	"""
	registers the agent in the Jabber server
	"""

        jid = xmpp.protocol.JID(self._aid.getName())
        name = jid.getNode()

        #TODO: Que pasa si no conectamos? Hay que controlarlo!!!
	c = ''
	while not c:
		# Try to connect. Wait if it fails
	        c = self.jabber.connect()
		if not c:
			time.sleep(0.005)

        if (self.jabber.auth(name,password,"spade") == None):
                raise NotImplementedError

        #print "auth ok", name
        self.jabber.RegisterHandler('message',self._jabber_messageCB)
        self.jabber.RegisterHandler('presence',self._jabber_presenceCB)

	self.jabber_process = jabberProcess(self.jabber, owner=self)
	self.jabber_process.start()
        #thread.start_new_thread(self._jabber_process, tuple())

    def _shutdown(self):

	self._kill()  # Doublecheck death	

	self.jabber_process._kill()

	#Stop the Behaviours
        for b in self._behaviourList:
            self.removeBehaviour(b)
        if (self._defaultbehaviour != None):
            self._defaultbehaviour.kill()
        #DeInit the Agent
        self.takeDown()

	self._alive = False


class Agent(AbstractAgent):
    """
    This is the main class which may be inherited to build a SPADE agent
    """
    def __init__(self, agentjid, password, port=5222, debug=[]):
        jid = xmpp.protocol.JID(agentjid)
        self.server = jid.getDomain()
	self.port = port
	self.debug = debug
        AbstractAgent.__init__(self, agentjid, self.server)
        self.jabber = xmpp.Client(self.server, self.port, self.debug)

	# Try to register
	try:
		#print "### Trying to register agent %s"%(agentjid)
        	self._register(password)
        except NotImplementedError:
		#print "### NotImplementedError: Could not register agent %s"%(agentjid)
		self.stop()
		return
	except:
		#print "### Could not register agent %s"%(agentjid)
		self.stop()
		return
		

	#print "### Agent %s registered"%(agentjid)
	#self._roster = self.jabber.getRoster()
        self.jabber.sendInitPresence()
	
	if not self.__register_in_AMS():
		print "Agent " + str(self.getAID().getName()) + " dying ..."
		sys.exit(-1)

    def _register(self, password, autoregister=True):
	"""
	registers the agent in the Jabber server
	"""

        jid = xmpp.protocol.JID(self._aid.getName())
        name = jid.getNode()

	c = ''
	while not c:
		# Try to connect. Wait if it fails
	        c = self.jabber.connect()
		if not c:
			time.sleep(0.005)
	#print "### Agent %s got connected to the server"%(self._aid.getName())

        #TODO:  Que pasa si no nos identificamos? Hay que controlarlo!!!
        #       Registrarse automaticamente o algo..
        if (self.jabber.auth(name,password,"spade") == None):
            #raise NotImplementedError
	   
	    #print "### Agent %s: First auth attempt failed"%(self._aid.getName())
 
	    if (autoregister == True):
                xmpp.features.getRegInfo(self.jabber,jid.getDomain())
                xmpp.features.register(self.jabber,jid.getDomain(),\
		{'username':name, 'password':str(password)})

		"""
		print "Going to disconnect"
		#self.jabber.reconnectAndReauth()
		self.jabber.disconnect()
		print "Disconnected"
		del self.jabber
		print "socket deleted"
        	self.jabber = xmpp.Client(self.server, self.port, self.debug)
		self.jabber.connect()
		print 'REconnected'
		"""


                if (self.jabber.auth(name,password,"spade") == None):
		#if not self.jabber.reconnectAndReauth():
	    	    print "### Agent %s: Second auth attempt failed"%(self._aid.getName())
                    raise NotImplementedError
            else:
                raise NotImplementedError
	    
	#print "### Agent %s got authed"%(self._aid.getName())

        self.jabber.RegisterHandler('message',self._jabber_messageCB)
        self.jabber.RegisterHandler('presence',self._jabber_presenceCB)

        #thread.start_new_thread(self._jabber_process, tuple())
	self.jabber_process = jabberProcess(self.jabber, owner=self)
	self.jabber_process.start()
	#print "### Agent %s: Started jabber process"%(self._aid.getName())
        

    def _shutdown(self):

        #Stop the Behaviours
        for b in self._behaviourList:
            self.removeBehaviour(b)
        if (self._defaultbehaviour != None):
            self._defaultbehaviour.kill()
        #DeInit the Agent

	"""
	try:
		del self._defaultbehaviour
		self._defaultbehaviour = None
	except:
		pass
	"""

	#self.kill()

        self.takeDown()

	if self._alivemutex.testandset():
		if not self.jabber_process.forceKill():
			if not self.__deregister_from_AMS():
				print "Agent " + str(self.getAID().getName()) + " dying without deregistering itself ..."
			self.jabber_process._kill()  # Kill jabber thread
		self._alive = False
	self._alivemutex.unlock()

	self._kill()  # Doublecheck death

    """
    def run(self):
	try:
	AbstractAgent.run(self)
	finally:
		self.shutdown()
    """

    def __register_in_AMS(self, state='active', ownership=None, debug=False):

	presence = xmpp.Presence(to=self.getAMS().getName(),frm=self.getName(),typ='subscribed')

	self.jabber.send(presence)

	if debug: print color_green + "Agent: " + color_yellow + str(self.getAID().getName()) + color_green + " registered correctly (inform)" + color_none
	return True

    def __register_in_AMS_with_ACL(self, state='active', ownership=None, debug=False):

	self._msg = ACLMessage.ACLMessage()
	self._msg.addReceiver( self.getAMS() )
	self._msg.setPerformative('request')
	self._msg.setLanguage('fipa-sl0')
	self._msg.setProtocol('fipa-request')
	self._msg.setOntology('FIPA-Agent-Management')
				
	content = "((action "
	content += str(self.getAID())
	content += "(register (ams-agent-description "
	content += ":name " + str(self.getAID())
	content += ":state "+state
	if ownership:
		content += ":ownership " + ownership
	content +=" ) ) ))"

	self._msg.setContent(content)
		
	self.send(self._msg)

	# We expect the initial answer from the AMS
	msg = self._receive(True,20)
	if (msg != None) and (str(msg.getPerformative()) == 'refuse'):
		print color_red + "There was an error initiating the register of agent: " + color_yellow + str(self.getAID().getName()) + color_red + " (refuse)" + color_none
		return False
	elif (msg != None) and (str(msg.getPerformative()) == 'agree'):
		print color_green + "Agent: " + color_yellow + str(self.getAID().getName()) + color_green + " initiating registering process (agree)" + color_none
	else:
		# There was no answer from the AMS or it answered something weird, so error
		print color_red + "There was an error initiating the register of agent: " + color_yellow + str(self.getAID().getName()) + color_none
		return False
			
	# Now we expect the real informative answer from the AMS
	msg = self._receive(True,20)
	if (msg != None) and (msg.getPerformative() == 'failure'):
		print color_red + "There was an error with the register of agent: " + color_yellow + str(self.getAID().getName()) + color_red + " (failure)" + color_none
		return False
	elif (msg != None) and (str(msg.getPerformative()) == 'inform'):
		print color_green + "Agent: " + color_yellow + str(self.getAID().getName()) + color_green + " registered correctly (inform)" + color_none
	else:
		# There was no real answer from the AMS or it answered something weird, so error
		print color_red + "There was an error with the register of agent: " + color_yellow + str(self.getAID().getName()) + color_none
		return False
	
	return True


    def __deregister_from_AMS(self, state=None, ownership=None, debug=False):
    
	presence = xmpp.Presence(to=self.getAMS().getName(),frm=self.getName(),typ='unsubscribed')

	self.jabber.send(presence)
	if debug: print color_green + "Agent: " + color_yellow + str(self.getAID().getName()) + color_green + " deregistered correctly (inform)" + color_none

	return True


    def __deregister_from_AMS_with_ACL(self, state=None, ownership=None, debug=False):

	_msg = ACLMessage.ACLMessage()
	_msg.addReceiver( self.getAMS() )
	_msg.setPerformative('request')
	_msg.setLanguage('fipa-sl0')
	_msg.setProtocol('fipa-request')
	_msg.setOntology('FIPA-Agent-Management')
				
	content = "((action "
	content += str(self.getAID())
	content += "(deregister (ams-agent-description "
	content += " :name " + str(self.getAID())
	if state:
		content += " :state "+state
	if ownership:
		content += " :ownership " + ownership
	content +=" ) ) ))"

	_msg.setContent(content)
		
	self.send(_msg)

	# We expect the initial answer from the AMS
	msg = self._receive(True,20)
	if (msg != None) and (str(msg.getPerformative()) == 'refuse'):
		print colors.color_red + "There was an error initiating the deregister of agent: " + colors.color_yellow + str(self.getAID().getName()) + colors.color_red + " (refuse)" + colors.color_none
		return False
	elif (msg != None) and (str(msg.getPerformative()) == 'agree'):
		print colors.color_green + "Agent: " + colors.color_yellow + str(self.getAID().getName()) + colors.color_green + " initiating deregistering process (agree)" + colors.color_none
	else:
		# There was no answer from the AMS or it answered something weird, so error
		print colors.color_red + "There was an error deregistering of agent: " + colors.color_yellow + str(self.getAID().getName()) + colors.color_none
		return False
			
	# Now we expect the real informative answer from the AMS
	msg = self._receive(True,20)
	if (msg != None) and (msg.getPerformative() == 'failure'):
		print "There was an error with the deregister of agent: " + str(self.getAID().getName()) + " (failure)"
		return False
	elif (msg != None) and (str(msg.getPerformative()) == 'inform'):
		print "Agent: " + str(self.getAID().getName()) + " deregistered correctly (inform)"
	else:
		# There was no real answer from the AMS or it answered something weird, so error
		print "There was an error with the deregister of agent: " + str(self.getAID().getName())
		return False
	
	return True


